package com.wind.test;

import com.wind.entity.User;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.Date;

/**
 * 测试： 增、删、改、查
 */
public class JpaTest02_增删改查 {

  private EntityManagerFactory entityManagerFactory;
  private EntityManager entityManager;
  private EntityTransaction entityTransaction;

  @Before
  public void init() {
    entityManagerFactory = Persistence.createEntityManagerFactory("JpaDemo");
    entityManager = entityManagerFactory.createEntityManager();
    entityTransaction = entityManager.getTransaction();
    entityTransaction.begin();
  }

  @After
  public void destroy() {
    entityTransaction.commit();
    entityManager.close();
    entityManagerFactory.close();
  }

  /*
    增：EntityManager.persistence()
      类似于 hibernate 的 save 方法. 使对象由临时状态变为持久化状态.
	  和 hibernate 的 save 方法的不同之处: 若对象有 id, 则不能执行 insert 操作, 而会抛出异常.
   */
  @Test
  public void testPersistence() {
    User user = new User();
    user.setLastName("Timi");
    user.setAge(5);
    user.setCreateTime(new Date());
    user.setBirth(new Date());

    // 设置 ID 会报错：detached entity passed to persist
    // 原因是： ID生成策略是自动，但又给ID手动设置值
    user.setId(100);

    // 保存
    entityManager.persist(user);

    // 插入后可以获取这个对象的ID
    System.out.println(user.getId());
  }

  /*
    删：EntityManager.remove()
      类似于 hibernate 中 Session 的 delete 方法. 把对象对应的记录从数据库中移除
      但注意: 该方法只能移除 持久化 对象. 而 hibernate 的 delete 方法实际上还可以移除 游离对象.
   */
  @Test
  public void testRemove() {
//    User user = new User();
//    user.setId(2);

    User user = entityManager.find(User.class, 2);
    entityManager.remove(user);
  }

  /*
    改：好像没单独的方法，需要借助 merge 通用方法。
   */


  /*
    查：EntityManager.find()
      类似于 hibernate 中 Session 的 get 方法.
   */
  @Test
  public void testFind() {
    User user = entityManager.find(User.class, 1);
    System.out.println("-------------------------------------");
    System.out.println(user);
  }

  /*
    懒加载的查：EntityManager.getReference()
      类似于 hibernate 中 Session 的 load 方法
   */
  @Test
  public void testGetReference(){
    User user = entityManager.getReference(User.class, 1);
    System.out.println(user.getClass().getName());  // 懒加载的代理对象：com.wind.entity.User_$$_javassist_0
    System.out.println("-------------------------------------");
//  entityTransaction.commit();
//	entityManager.close();  // 关闭了
    System.out.println(user); // 再调用代理对象的时候就报错了：org.hibernate.LazyInitializationException: could not initialize proxy - no Session
  }


  /**
    综合方法：EntityManager.merge()
      类似于 hibernate Session 的 saveOrUpdate 方法.
   */
  /*
    情况1：若传入的是一个临时对象：
      1）会创建一个新的对象
      2）把临时对象的属性复制到新的对象中
      3）然后对新的对象执行持久化操作
      所以 新的对象中有 id, 但以前的临时对象中没有 id.
   */
  @Test
  public void testMerge1(){
    User user1 = new User();
    user1.setAge(18);
    user1.setBirth(new Date());
    user1.setCreateTime(new Date());
    user1.setLastName("CC");

    User user2 = entityManager.merge(user1);

    System.out.println("user1#id:" + user1.getId());  // user1#id:null
    System.out.println("user2#id:" + user2.getId());  // user2#id:4
  }

  /*
    情况2：若传入的是一个游离对象, 即传入的对象有 ID：
      1）若在 EntityManager 缓存中没有该对象
      2）若在数据库中也没有对应的记录
      3）JPA 会创建一个新的对象, 然后把当前游离对象的属性复制到新创建的对象中
      4）对新创建的对象执行 insert 操作.
   */
  @Test
  public void testMerge2(){
    User user1 = new User();
    user1.setAge(18);
    user1.setBirth(new Date());
    user1.setCreateTime(new Date());
    user1.setLastName("DD");

    user1.setId(100);

    User user2 = entityManager.merge(user1);

    System.out.println("user1#id:" + user1.getId());  // user1#id:100
    System.out.println("user2#id:" + user2.getId());  // user2#id:5（主键还是自增策略）
  }

  /*
    情况3：若传入的是一个游离对象, 即传入的对象有 ID：
      1）若在 EntityManager 缓存中没有该对象
      2）若在数据库中也有对应的记录
      3）JPA 会查询对应的记录, 然后返回该记录对一个的对象, 再然后会把游离对象的属性复制到查询到的对象中.
      4）对查询到的对象执行 update 操作.
   */
  @Test
  public void testMerge3(){
    User user1 = new User();
    user1.setAge(18);
    user1.setBirth(new Date());
    user1.setCreateTime(new Date());
    user1.setLastName("EE");

    user1.setId(4);

    User user2 = entityManager.merge(user1);

    System.out.println(user1 == user2); //false
  }

  /*
    情况4：若传入的是一个游离对象, 即传入的对象有 ID：
      1）若在 EntityManager 缓存中有对应的对象
      2）JPA 会把游离对象的属性复制到查询到EntityManager 缓存中的对象中.
      3）EntityManager 缓存中的对象执行 UPDATE.
   */
  @Test
  public void testMerge4(){
    // user1是游离对象
    User user1 = new User();
    user1.setAge(19);
    user1.setBirth(new Date());
    user1.setCreateTime(new Date());
    user1.setLastName("DD");

    user1.setId(4);

    User user2 = entityManager.find(User.class, 4);

    // JPA 可以这样玩，但是在 Hibernate 中会报错，因为 Session 跟 ID 是4的两个对象关联了
    entityManager.merge(user1);

    System.out.println(user1 == user2); //false
  }

}
